﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using System.Globalization;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.IO.Compression;
using System.Drawing;
using System.Threading;

namespace Zsea.Browser
{
    public class Browser
    {
        // Fields
        private CookieContainer _cc;
        private WebHeaderCollection _headers;
        private bool _baseUrlIsLock = false;


        // Methods
        public Browser()
        {
            this._cc = new CookieContainer();
            this._headers = new WebHeaderCollection();
        }

        public Browser(bool CreateDefault)
            : this(CreateDefault, string.Empty, null)
        {
        }

        public Browser(bool CreateDefault, string refere)
            : this(CreateDefault, refere, null)
        {
        }

        public Browser(bool CreateDefault, string refere, Encoding encoding)
        {
            this._cc = new CookieContainer();
            this._headers = new WebHeaderCollection();
            if (CreateDefault)
            {
                this.Accept = "*/*";
                this.KeepAlive = true;
                this.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3)";
                this.ContentType = "application/x-www-form-urlencoded";
                this.Headers.Add("Accept-Encoding", "gzip, deflate");
                this.Headers.Add("Accept-Language", "zh-CN");
            }
            if (!string.IsNullOrEmpty(refere))
            {
                this.Referer = refere;
            }
            if (encoding != null)
            {
                this.Encode = encoding;
            }
        }

        private HttpWebRequest _CreateHttpWebRequest(string v, string url, Method m)
        {
            HttpWebRequest request = null;
            if ((m == Method.Get) && !string.IsNullOrEmpty(v))
            {
                if (url.IndexOf('?') == -1)
                {
                    url = url + "?";
                }
                if (!Regex.IsMatch(url, @"[\?&]$", RegexOptions.IgnoreCase))
                {
                    url = url + "&";
                }
                string[] strArray = v.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < strArray.Length; i++)
                {
                    Match match = Regex.Match(strArray[i], @"(.+?)\=(.+)", RegexOptions.IgnoreCase);
                    string str = string.Empty;
                    string str2 = string.Empty;
                    if (match != null)
                    {
                        str = match.Groups[1].Value;
                        str2 = match.Groups[2].Value;
                    }
                    string str4 = url;
                    url = str4 + HttpUtility.UrlEncode(str, this.Encode) + "=" + HttpUtility.UrlEncode(str2, this.Encode) + "&";
                }
            }
            if (!string.IsNullOrEmpty(this.BaseUrl))
            {
                url = new Uri(new Uri(this.BaseUrl), url).ToString();
                if (url.StartsWith("https://", true, CultureInfo.CurrentCulture))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(Zsea.Browser.Browser.CheckValidationResult);
                }
            }
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                
                this.Url = url;
                if (!this._baseUrlIsLock)
                {
                    this.BaseUrl = url;
                }
            }
            catch
            {
                return null;
            }
            request.AllowAutoRedirect = false;
            if (this.WebProxy != null)
            {
                request.Proxy = this.WebProxy;
            }
            if (this.Cookies == null)
            {
                this._cc = new CookieContainer();
            }
            request.CookieContainer = this._cc;
            if (m == Method.Get)
            {
                request.Method = "Get";
            }
            else
            {
                request.Method = "Post";
            }
            if (!string.IsNullOrEmpty(this.Accept))
            {
                request.Accept = this.Accept;
            }
            request.KeepAlive = this.KeepAlive;
            if (!string.IsNullOrEmpty(this.ContentType))
            {
                request.ContentType = this.ContentType;
            }
            foreach (string str3 in this.Headers)
            {
                request.Headers.Add(str3, this.Headers[str3]);
            }
            if (!string.IsNullOrEmpty(this.UserAgent))
            {
                request.UserAgent = this.UserAgent;
            }
            request.ServicePoint.Expect100Continue = false;
            if (!string.IsNullOrEmpty(this.Referer))
            {
                request.Referer = this.Referer;
            }
            if (this.Encode == null)
            {
                this.Encode = Encoding.GetEncoding("GB2312");
            }
            if (m == Method.Post)
            {
                byte[] bytes = this.Encode.GetBytes(v);
                request.ContentLength = bytes.Length;
                try
                {
                    Stream requestStream = request.GetRequestStream();
                    requestStream.Write(bytes, 0, bytes.Length);
                    requestStream.Close();
                }
                catch
                {
                    try
                    {
                        request.Abort();
                    }
                    catch
                    {
                    }
                    return null;
                }
            }
            return request;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }

        public static RequestResult Request(string url)
        {
            return Request(string.Empty, url, Method.Get, new CookieContainer(), string.Empty, null, null);
        }

        public static RequestResult Request(string url, WebProxy proxy)
        {
            return Request(string.Empty, url, Method.Get, new CookieContainer(), string.Empty, proxy, null);
        }

        public static RequestResult Request(string url, Encoding encode)
        {
            return Request(string.Empty, url, Method.Get, new CookieContainer(), string.Empty, null, encode);
        }

        public static RequestResult Request(string v, string url, Method m, CookieContainer cookie, string Referer, WebProxy proxy, Encoding encode)
        {
            HttpWebRequest request = null;
            if ((m == Method.Get) && !string.IsNullOrEmpty(v))
            {
                if (url.IndexOf('?') == -1)
                {
                    url = url + "?";
                }
                if (!Regex.IsMatch(url, @"[\?&]$", RegexOptions.IgnoreCase))
                {
                    url = url + "&";
                }
                string[] strArray = v.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < strArray.Length; i++)
                {
                    Match match = Regex.Match(strArray[i], @"(.+?)\=(.+)", RegexOptions.IgnoreCase);
                    string str = string.Empty;
                    string str2 = string.Empty;
                    if (match != null)
                    {
                        str = match.Groups[1].Value;
                        str2 = match.Groups[2].Value;
                    }
                    string str5 = url;
                    url = str5 + HttpUtility.UrlEncode(str, encode) + "=" + HttpUtility.UrlEncode(str2, encode) + "&";
                }
            }
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
            }
            catch
            {
                return null;
            }
            request.AllowAutoRedirect = false;
            if (proxy != null)
            {
                request.Proxy = proxy;
                request.Headers.Add("HTTP_X_FORWARDED_FOR", proxy.Address.Host);
            }
            if (cookie == null)
            {
                cookie = new CookieContainer();
            }
            request.CookieContainer = cookie;
            if (m == Method.Get)
            {
                request.Method = "Get";
            }
            else
            {
                request.Method = "Post";
            }
            request.Accept = "*/*";
            request.KeepAlive = true;
            request.ContentType = "application/x-www-form-urlencoded";
            request.Headers.Add("Accept-Language", "zh-cn");
            request.Headers.Add("UA-CPU", "x86");
            request.Headers.Add("Accept-Encoding", "gzip, deflate");
            request.Headers.Add("Cache-Control", "no-cache");
            request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)";
            request.ServicePoint.Expect100Continue = false;
            if (!string.IsNullOrEmpty(Referer))
            {
                request.Referer = Referer;
            }
            if (encode == null)
            {
                encode = Encoding.GetEncoding("GB2312");
            }
            if (m == Method.Post)
            {
                byte[] buffer = encode.GetBytes(v);
                request.ContentLength = buffer.Length;
                try
                {
                    Stream requestStream = request.GetRequestStream();
                    requestStream.Write(buffer, 0, buffer.Length);
                    requestStream.Close();
                }
                catch
                {
                    try
                    {
                        request.Abort();
                    }
                    catch
                    {
                    }
                    return null;
                }
            }
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException exception)
            {
                return new RequestResult { HttpStatusCode = HttpStatusCode.ExpectationFailed, WebExceptionStatus = exception.Status };
            }
            if (response.StatusCode != HttpStatusCode.OK)
            {
                RequestResult cookie3 = new RequestResult
                {
                    GotoUrl = response.Headers["Location"],
                    HttpStatusCode = response.StatusCode,
                    CookieContainer = request.CookieContainer
                };
                response.Close();
                return cookie3;
            }
            Stream responseStream = response.GetResponseStream();
            if (!string.IsNullOrEmpty(response.CharacterSet))
            {
                try
                {
                    string characterSet = response.CharacterSet;
                    if (response.CharacterSet.ToUpper() == "ISO-8859-1")
                    {
                        characterSet = "GB2312";
                    }
                    encode = Encoding.GetEncoding(characterSet);
                }
                catch
                {
                }
            }
            if (response.ContentEncoding.ToLower() == "gzip")
            {
                responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
            }
            if (response.ContentEncoding.ToLower() == "deflate")
            {
                responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
            }
            byte[] bytes = StreamToByte(responseStream);
            string str4 = encode.GetString(bytes);
            responseStream.Close();
            RequestResult cookie4 = new RequestResult
            {
                CookieContainer = request.CookieContainer,
                Html = str4,
                Bytes = bytes,
                HttpStatusCode = response.StatusCode
            };
            response.Close();
            return cookie4;
        }

        public static RequestResult Request(string v, string url, Method m, CookieContainer cookie, string Referer, WebProxy proxy, Encoding encode, int gototimes)
        {
            gototimes--;
            RequestResult cookie2 = null;
            while (gototimes >= 0)
            {
                Thread.Sleep(1);
                cookie2 = Request(v, url, m, cookie, Referer, proxy, encode);
                if (cookie2 == null)
                {
                    return null;
                }
                if (!string.IsNullOrEmpty(cookie2.GotoUrl))
                {
                    m = Method.Get;
                    cookie = cookie2.CookieContainer;
                    Referer = url;
                    url = cookie2.GotoUrl;
                }
                else
                {
                    return cookie2;
                }
                gototimes--;
            }
            return cookie2;
        }

        //public static ImageAndCookie getImageAndCookie(string url)
        //{
        //    return getImageAndCookie(string.Empty, url, Method.Get, new CookieContainer(), string.Empty, null, null);
        //}

        //public static ImageAndCookie getImageAndCookie(string v, string url, Method m, CookieContainer cookie, string Referer, WebProxy proxy, Encoding encode)
        //{
        //    HttpWebRequest request = null;
        //    try
        //    {
        //        request = (HttpWebRequest)WebRequest.Create(url);
        //    }
        //    catch
        //    {
        //        return null;
        //    }
        //    request.AllowAutoRedirect = false;
        //    if (proxy != null)
        //    {
        //        request.Proxy = proxy;
        //        request.Headers.Add("HTTP_X_FORWARDED_FOR", proxy.Address.Host);
        //    }
        //    if (cookie == null)
        //    {
        //        cookie = new CookieContainer();
        //    }
        //    request.CookieContainer = cookie;
        //    if (m == Method.Get)
        //    {
        //        request.Method = "Get";
        //    }
        //    else
        //    {
        //        request.Method = "Post";
        //    }
        //    request.Accept = "*/*";
        //    request.KeepAlive = true;
        //    request.ContentType = "application/x-www-form-urlencoded";
        //    request.Headers.Add("Accept-Language", "zh-cn");
        //    request.Headers.Add("UA-CPU", "x86");
        //    request.Headers.Add("Accept-Encoding", "gzip, deflate");
        //    request.Headers.Add("Cache-Control", "no-cache");
        //    request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)";
        //    request.ServicePoint.Expect100Continue = false;
        //    if (!string.IsNullOrEmpty(Referer))
        //    {
        //        request.Referer = Referer;
        //    }
        //    if (encode == null)
        //    {
        //        encode = Encoding.GetEncoding("GB2312");
        //    }
        //    if (m == Method.Post)
        //    {
        //        try
        //        {
        //            byte[] bytes = encode.GetBytes(v);
        //            request.ContentLength = bytes.Length;
        //            Stream requestStream = request.GetRequestStream();
        //            requestStream.Write(bytes, 0, bytes.Length);
        //            requestStream.Close();
        //        }
        //        catch
        //        {
        //            return null;
        //        }
        //    }
        //    HttpWebResponse response = null;
        //    try
        //    {
        //        response = (HttpWebResponse)request.GetResponse();
        //    }
        //    catch
        //    {
        //        return new ImageAndCookie { HttpStatusCode = HttpStatusCode.Unused };
        //    }
        //    if (response.StatusCode != HttpStatusCode.OK)
        //    {
        //        ImageAndCookie cookie3 = new ImageAndCookie
        //        {
        //            GotoUrl = response.Headers["Location"],
        //            HttpStatusCode = response.StatusCode,
        //            CookieContainer = request.CookieContainer
        //        };
        //        response.Close();
        //        return cookie3;
        //    }
        //    Stream responseStream = response.GetResponseStream();
        //    if (!string.IsNullOrEmpty(response.CharacterSet))
        //    {
        //        try
        //        {
        //            string characterSet = response.CharacterSet;
        //            if (response.CharacterSet.ToUpper() == "ISO-8859-1")
        //            {
        //                characterSet = "GB2312";
        //            }
        //            encode = Encoding.GetEncoding(characterSet);
        //        }
        //        catch
        //        {
        //        }
        //    }
        //    if (response.ContentEncoding.ToLower() == "gzip")
        //    {
        //        responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
        //    }
        //    if (response.ContentEncoding.ToLower() == "deflate")
        //    {
        //        responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
        //    }
        //    Image image = null;
        //    try
        //    {
        //        image = new Bitmap(responseStream);
        //    }
        //    catch
        //    {
        //    }
        //    responseStream.Close();
        //    response.Close();
        //    if (image == null)
        //    {
        //        return null;
        //    }
        //    return new ImageAndCookie { CookieContainer = request.CookieContainer, Image = image, HttpStatusCode = HttpStatusCode.OK };
        //}

        public RequestResult Request(string v, string url, Method m)
        {
            HttpWebRequest request = this._CreateHttpWebRequest(v, url, m);
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch
            {
                return new RequestResult { HttpStatusCode = HttpStatusCode.NotFound };
            }
            if (response.StatusCode != HttpStatusCode.OK)
            {
                RequestResult cookie2 = new RequestResult
                {
                    GotoUrl = response.Headers["Location"],
                    HttpStatusCode = response.StatusCode,
                    CookieContainer = request.CookieContainer
                };
                response.Close();
                return cookie2;
            }
            Stream responseStream = response.GetResponseStream();
            if (!string.IsNullOrEmpty(response.CharacterSet))
            {
                try
                {
                    string characterSet = response.CharacterSet;
                    if (response.CharacterSet.ToUpper() == "ISO-8859-1")
                    {
                        characterSet = "GB2312";
                    }
                    this.Encode = Encoding.GetEncoding(characterSet);
                }
                catch
                {
                }
            }
            if (response.ContentEncoding.ToLower() == "gzip")
            {
                responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
            }
            if (response.ContentEncoding.ToLower() == "deflate")
            {
                responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
            }
            byte[] bytes = StreamToByte(responseStream);
            string str2 = this.Encode.GetString(bytes);
            responseStream.Close();
            RequestResult cookie3 = new RequestResult
            {
                CookieContainer = request.CookieContainer,
                Html = str2,
                Bytes = bytes,
                HttpStatusCode = response.StatusCode
            };
            response.Close();
            return cookie3;
        }

        public void LockBaseUrl()
        {
            this._baseUrlIsLock = true;
        }
        public void UnLockBaseUrl()
        {
            this._baseUrlIsLock = false;
        }

        public void SaveAs(string v, string url, Method m, string savepath)
        {
            HttpWebRequest request = this._CreateHttpWebRequest(v, url, m);
            Stream responseStream = ((HttpWebResponse)request.GetResponse()).GetResponseStream();
            byte[] bytes = StreamToByte(responseStream);
            File.WriteAllBytes(savepath, bytes);
            responseStream.Close();
        }

        private static byte[] StreamToByte(Stream stream)
        {
            List<byte> list = new List<byte>();
            for (int i = stream.ReadByte(); i != -1; i = stream.ReadByte())
            {
                list.Add((byte)i);
            }
            return list.ToArray();
        }

        // Properties
        public string Accept { get; set; }

        public string ContentType { get; set; }

        public CookieContainer Cookies
        {
            get
            {
                return this._cc;
            }
        }

        public Encoding Encode { get; set; }

        public WebHeaderCollection Headers
        {
            get
            {
                return this._headers;
            }
        }

        public bool KeepAlive { get; set; }

        public string Referer { get; set; }

        public string Url { get; private set; }
        public string BaseUrl { get; private set; }

        public string UserAgent { get; set; }

        public WebProxy WebProxy { get; set; }
    }





}
